package online.heycm.platform.canary.gateway;

import lombok.extern.slf4j.Slf4j;
import online.heycm.platform.canary.common.CanaryProperties;
import online.heycm.platform.canary.common.CanaryRule;
import online.heycm.platform.canary.common.CanaryRuleCache;
import online.heycm.platform.common.tools.Jackson;
import online.heycm.platform.nacos.NacosConfListener;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.gateway.config.LoadBalancerProperties;
import org.springframework.cloud.gateway.filter.ReactiveLoadBalancerClientFilter;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;

import java.util.List;

/**
 * 自动装配注册 网关负载均衡
 *
 * @author heycm
 * @since 2023/12/30 10:00
 */
@Slf4j
@Configuration(proxyBeanMethods = false)
@EnableConfigurationProperties(CanaryProperties.class)
public class CanaryAutoConfiguration {

    public CanaryAutoConfiguration() {
        log.info("CanaryAutoConfiguration init...");
    }

    /**
     * 注册 GatewayCanaryLoadBalancer
     */
    @Bean
    // @ConditionalOnBean(LoadBalancerClientFactory.class)
    public ReactorLoadBalancer<ServiceInstance> loadBalancer(Environment environment,
                                                             LoadBalancerClientFactory loadBalancerClientFactory,
                                                             CanaryProperties canaryProperties, NacosConfListener nacosConfListener) {
        refreshCanaryRuleCache(canaryProperties, nacosConfListener);
        String name = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        return new GatewayCanaryLoadBalancer(
                loadBalancerClientFactory.getLazyProvider(name, ServiceInstanceListSupplier.class), name);
    }

    @Bean
    public ReactiveLoadBalancerClientFilter reactiveLoadBalancerClientFilter(LoadBalancerClientFactory clientFactory,
                                                                             LoadBalancerProperties properties) {
        return new CanaryFilter(clientFactory, properties);
    }

    /**
     * Nacos 灰度配置监听
     */
    private void refreshCanaryRuleCache(CanaryProperties canaryProperties, NacosConfListener nacosConfListener) {
        nacosConfListener.addListener(canaryProperties.getDataId(), canaryProperties.getGroup(), config -> {
            List<CanaryRule> rules = Jackson.toList(config, CanaryRule.class);
            CanaryRuleCache.update(rules);
        });
    }

}
